/*************************************************************************
 *                                                                       *
 * This file is part of the DogosFrame distribution.  For full copyright *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 *                                                                       *
 *************************************************************************/

#ifndef DOGOS_include_COMMON_tbox_PIO_h
#define DOGOS_include_COMMON_tbox_PIO_h

#include <fstream>
#include <iostream>
#include <string>

namespace DOGOS
{

/**
 * Class PIO manages parallel stream I/O and logging.  Static member
 * function initialize() must be called before any of the parallel streams
 * pout, perr, or plog may be used.  Routine finalize() should also be called
 * before termination of the program.  Note that these functions are currently
 * called by the DOGOS manager startup and shutdown routines and therefore
 * should not be explicitly called by an application code.
 *
 * By default, logging is disabled.  To enable logging, call one of the
 * routines log_only_node_zero() or log_all_nodes().  Logging may be suspended
 * and resumed.
 */
struct PIO
{
    /**
     * Initialize the parallel I/O streams.  This routine must be called
     * before using pout, perr, or plog.  This routine is automatically
     * invoked by the DOGOS library start-up routines.  This routine
     * must be called after the MPI routines have been initialized.
     */
    static void
    initialize();

    /**
     * Shut down the parallel I/O streams and close log files.  This routine
     * must be called before program termination and is currently invoked from
     * the DOGOS library shutdown procedure.
     */
    static void
    finalize();

    /**
     * Log messages for node zero only to the specified file_name.  All output
     * to pout, perr, and plog on node zero will go to the log file.
     */
    static void
    log_only_node_zero(
        const std::string& file_name);

    /**
     * Log messages from all nodes.  The diagnostic data for processor XXXXX
     * will be sent to a file with the name file_name.XXXXX, where file_name is
     * the function argument.
     */
    static void
    log_all_nodes(
        const std::string& file_name);

    /**
     * Temporarily suspend file logging.  Log file output will be discarded,
     * although the output file will not be closed.  Logging can be resumed
     * by calling member function resume_logging().
     */
    static void
    suspend_logging();

    /**
     * Resume logging after logging was suspended via member function
     * suspend_logging().
     */
    static void
    resume_logging();

private:

    static void
    shutdown_filestream();                // shutdown the log filestream

    static int s_rank;                   // processor rank in MPI group
    static std::ofstream* s_filestream;  // NULL or log filestream
};

/**
 * Parallel output stream pout writes to the standard output from node zero
 * only.  Output from other nodes is ignored.  If logging is enabled, then
 * output is mirrored to the log stream, as well.
 */
extern std::ostream POUT;

/**
 * Parallel output stream perr writes to the standard error from all nodes.
 * Output is prepended with the processor number.  If logging is enabled,
 * then output is mirrored to the log stream, as well.
 */
extern std::ostream PERR;

/**
 * Parallel output stream plog writes output to the log file.  When logging
 * from multiple processors, the processor number is appended to the file_name.
 */
extern std::ostream PLOG;

}

#include "COMMON/tbox/PIO.inl"

#endif
